package com.tools.common.thread;

import com.tools.common.object.Note;

import java.util.Objects;
import java.util.concurrent.*;

/**
 * 自定义线程池的基础配置对象
 * 默认设置了缺省值，可直接构造使用
 * */
@Note("自定义线程池的基础配置对象。" +
        "默认设置了缺省值，可直接构造使用")
public class ThreadPoolSource {

    @Note("核心线程数，默认为 CPU 密集型（CPU 核心数 + 1）")
    private int coreSize = ThreadKit.getCPUIntensiveType();

    @Note("线程池允许的最大线程数，生产环境时可以调大点")
    private int maxSize = 50;

    @Note("当真正的线程大于核心线程时，多出来的部分保留在池中多长时间")
    private long keepAliveTime = 10;

    @Note("上面 keepAliveTime 的单位，默认是 10 分钟")
    private TimeUnit keepAliveTimeunit = TimeUnit.MINUTES;

    @Note("线程池要执行的任务队列的容量")
    private int queueCapacity = this.coreSize * 2;

    @Note("线程池要执行的任务队列。" +
            "ArrayBlockingQueue：数组实现的有界队列。可以设置公平性。如果非公平可以插队执行，公平则等待时间最长的执行。非公平的吞吐量大于公平的。" +
            "LinkedBlockingQueue：链表实现的无界队列。只会创建核心数的线程，最大线程数失效。" +
            "SynchronousQueue：来多少任务就创多少线程。核心线程数满了就继续创建新线程执行，不会将任务放进队列阻塞。" +
            "PriorityBlockingQueue：自定义权重优先级的无界队列，通过 Comparator 指定优先级规则。" +
            "DelayedWorkQueue：按延迟时间排序队列内的任务，采用堆的结构。队列的长度取决于已经到期但尚未执行的延迟任务数量。")
    private BlockingQueue<Runnable> workQueue;

    @Note("线程池内创建的线程名称的默认前缀")
    private String threadPrefix = "dawn-";

    @Note("线程的创建工厂，可自行 implements ThreadFactory 接口实现，或用以下方式获取：" +
            "1.Executors.defaultThreadFactory()" +
            "2.Executors.privilegedThreadFactory()" +
            "另外，本工具自行实现了一个 OwnThreadFactory 也可以拿来用")
    private ThreadFactory threadFactory;

    @Note("当队列满了，且线程池大小已达到最大限制大小时，所执行的拒绝策略，此处默认为中断并抛出异常。" +
            "有以下可选值：" +
            "ThreadPoolExecutor.DiscardPolicy() --- 丢弃策略，对新任务不做任何处理。" +
            "ThreadPoolExecutor.AbortPolicy() --- 中止策略，即抛出异常中止程序运行。" +
            "ThreadPoolExecutor.CallerRunsPolicy() --- 优先处理，优先执行新的任务。" +
            "ThreadPoolExecutor.DiscardOldestPolicy() --- 丢弃最老的任务，丢弃队列中最老的任务，再将新的任务放入队列中")
    private RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();



    public ThreadPoolSource() {}

    public static ThreadPoolSource of() {
        return new ThreadPoolSource();
    }

    /* *******************************************************************************************
     *
     *           Getter / Setter 方法
     *
     * *******************************************************************************************
     * */

    public int getCoreSize() {
        return coreSize;
    }

    public void setCoreSize(Integer coreSize) {
        this.coreSize = (coreSize == null || coreSize <= 0) ? this.coreSize : coreSize;
    }

    public int getMaxSize() {
        return maxSize;
    }

    public void setMaxSize(Integer maxSize) {
        this.maxSize = (maxSize == null || maxSize <= 0) ? this.maxSize : maxSize;
    }

    public long getKeepAliveTime() {
        return keepAliveTime;
    }

    public void setKeepAliveTime(Long keepAliveTime) {
        this.keepAliveTime = (keepAliveTime == null || keepAliveTime <= 0) ? this.keepAliveTime : keepAliveTime;
    }

    public TimeUnit getKeepAliveTimeunit() {
        return keepAliveTimeunit;
    }

    public void setKeepAliveTimeunit(TimeUnit keepAliveTimeunit) {
        this.keepAliveTimeunit = (keepAliveTimeunit == null) ? this.keepAliveTimeunit : keepAliveTimeunit;
    }

    public int getQueueCapacity() {
        return queueCapacity;
    }

    public void setQueueCapacity(Integer queueCapacity) {
        this.queueCapacity = (queueCapacity == null || queueCapacity < 0) ? this.queueCapacity : queueCapacity;
    }

    public BlockingQueue<Runnable> getWorkQueue() {
        if(workQueue == null) {
            this.workQueue = (queueCapacity > 0)
                    ? new LinkedBlockingQueue<>(queueCapacity)
                    : new SynchronousQueue<>();
        }
        return workQueue;
    }

    public void setWorkQueue(BlockingQueue<Runnable> workQueue) {
        this.workQueue = workQueue;
    }

    public ThreadFactory getThreadFactory() {
        if(threadFactory == null) {
            threadFactory = new OwnThreadFactory(threadPrefix, false, Thread.NORM_PRIORITY);
        }
        return threadFactory;
    }

    public void setThreadFactory(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
    }

    public RejectedExecutionHandler getHandler() {
        return handler;
    }

    public void setHandler(RejectedExecutionHandler handler) {
        this.handler = (handler == null) ? this.handler : handler;
    }

    public String getThreadPrefix() {
        return (threadPrefix == null) ? "" : threadPrefix;
    }

    public void setThreadPrefix(String threadPrefix) {
        this.threadPrefix = threadPrefix;
    }

    @Override
    public String toString() {
        return "ThreadPoolBuilder{" +
                "coreSize=" + coreSize +
                ", maxSize=" + maxSize +
                ", threadPrefix='" + threadPrefix + '\'' +
                ", keepAliveTime=" + keepAliveTime +
                ", keepAliveTimeunit=" + keepAliveTimeunit +
                ", queueCapacity=" + queueCapacity +
                ", workQueue=" + workQueue +
                ", threadFactory=" + threadFactory +
                ", handler=" + handler +
                '}';
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ThreadPoolSource that = (ThreadPoolSource) o;
        return coreSize == that.coreSize && maxSize == that.maxSize && keepAliveTime == that.keepAliveTime && queueCapacity == that.queueCapacity && keepAliveTimeunit == that.keepAliveTimeunit && Objects.equals(workQueue, that.workQueue) && Objects.equals(threadFactory, that.threadFactory) && Objects.equals(handler, that.handler) && Objects.equals(threadPrefix, that.threadPrefix);
    }

    @Override
    public int hashCode() {
        return Objects.hash(coreSize, maxSize, keepAliveTime, keepAliveTimeunit, queueCapacity, workQueue, threadFactory, handler, threadPrefix);
    }


    /* *******************************************************************************************
     *
     *           链式方法
     *
     * *******************************************************************************************
     * */


    public ThreadPoolSource coreSize(int coreSize) {
        this.setCoreSize(coreSize);
        return this;
    }

    public ThreadPoolSource maxSize(int maxSize) {
        this.setMaxSize(maxSize);
        return this;
    }

    public ThreadPoolSource coreSize(Long keepAliveTime) {
        this.setKeepAliveTime(keepAliveTime);
        return this;
    }

    public ThreadPoolSource coreSize(TimeUnit keepAliveTimeunit) {
        this.setKeepAliveTimeunit(keepAliveTimeunit);
        return this;
    }

    public ThreadPoolSource queueCapacity(int queueCapacity) {
        this.setQueueCapacity(queueCapacity);
        return this;
    }

    public ThreadPoolSource workQueue(BlockingQueue<Runnable> workQueue) {
        this.setWorkQueue(workQueue);
        return this;
    }

    public ThreadPoolSource threadFactory(ThreadFactory threadFactory) {
        this.setThreadFactory(threadFactory);
        return this;
    }

    public ThreadPoolSource handler(RejectedExecutionHandler handler) {
        this.setHandler(handler);
        return this;
    }

    public ThreadPoolSource threadPrefix(String threadPrefix) {
        this.setThreadPrefix(threadPrefix);
        return this;
    }
}
